2023.6.19 CNN + MNISTのサンプル(C×2+F×2)【torch】
(conv + ReLU + MaxPooling)×2 + FC×2
convとpooling層の各種パラメータを調整可能にした、画像サイズが小さくなりすぎなければ対応可能の筈
結果は./result/以下の日付+時刻に格納する。
code:python
import torch
import torch.nn as nn
import torch.nn.functional as f
import matplotlib.pyplot as plt
import sys, numpy, time
from sklearn.model_selection import train_test_split
import datetime
import os
from sklearn.datasets import fetch_openml
##########
class Net(nn.Module):
def __init__(self, args):
super().__init__()
# Channel number
# Conv-layer
# Pooling, Window & Stride size
# FC-layer
OUTPUT = args'OUTPUT' # for output FC-layer #
OH1 = int(( H1 + 2*P1 - FH1)/S1 + 1) # conv1への入力、タテ
OW1 = int(( W1 + 2*P1 - FW1)/S1 + 1) # conv1への入力、ヨコ
OHP1 = int(OH1 // POOL1) # Pooling1からの出力、タテ
OWP1 = int(OW1 // POOL1) # Pooling1からの出力、ヨコ
OH2 = int((OHP1 + 2*P2 - FH2)/S2 + 1) # conv2への入力、タテ
OW2 = int((OWP1 + 2*P2 - FW2)/S2 + 1) # conv2への入力、ヨコ
OHP2 = int(OH2 // POOL2) # Pooling2からの出力、タテ
OWP2 = int(OW2 // POOL2) # Pooling2からの出力、ヨコ
print(
'output from conv1 :', OH1, OW1,
', outout from pool1 :', OHP1, OWP1,
', output from conv2 :', OH2, OW2,
', outout from pool2 :', OHP2, OWP2
, file=fp)
print(
'output from conv1 :', OH1, OW1,
', outout from pool1 :', OHP1, OWP1,
', output from conv2 :', OH2, OW2,
', outout from pool2 :', OHP2, OWP2
)
self.relu = nn.ReLU()
self.pool1 = nn.MaxPool2d(POOL1, stride=POOL1)
self.pool2 = nn.MaxPool2d(POOL2, stride=POOL2)
self.softmax = nn.Softmax(dim=1)
self.conv1 = nn.Conv2d(CH1_i, CH1_o, kernel_size=(FH1, FW1), padding=P1, stride=S1)
self.conv2 = nn.Conv2d(CH2_i, CH2_o, kernel_size=(FH2, FW2), padding=P2, stride=S2)
self.fc1 = nn.Linear(CH2_o*OHP2*OWP2, HIDDEN_FC)
self.fc2 = nn.Linear(HIDDEN_FC, OUTPUT)
def forward(self, x):
x = self.conv1(x)
x = self.relu(x)
x = self.pool1(x)
x = self.conv2(x)
x = self.relu(x)
x = self.pool2(x)
x = x.view(x.size()0, -1) x = self.fc1(x)
x = self.relu(x)
x = self.fc2(x)
x = self.softmax(x)
return x
##########
def get_datename():
dt = datetime.datetime.now()
result = str(dt.year)
result = result + str(dt.month).zfill(2)
result = result + str(dt.day).zfill(2) + '_'
result = result + str(dt.hour).zfill(2)
result = result + str(dt.minute).zfill(2)
result = result + str(dt.second).zfill(2)
return result
##########
# 結果の保存用
dirname = './result/' + get_datename()
filename = 'result.md'
os.makedirs(dirname)
fp = open(dirname + '/' + filename, mode='w')
# データセットの取得
dataset = fetch_openml('mnist_784', data_home='~/scikit_learn_data', cache=True, parser='auto')
X = dataset'data'.to_numpy() # X = torch.tensor(X, dtype=torch.float32).view(-1, 28, 28) # (70000, 28, 28)
X = torch.unsqueeze(X, dim=1) # ここでチャネル数1にしておく (70000, 1, 28, 28)
y = dataset'target'.astype(int).to_numpy() y = torch.tensor(y) # (70000, )
test_size = 0.25
random_state = 42
output = 10
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=test_size, random_state=random_state
)
y_train_onehot = f.one_hot(y_train, num_classes=output).float()
y_test_onehot = f.one_hot(y_test, num_classes=output).float()
train_dataset = torch.utils.data.TensorDataset(X_train, y_train_onehot)
train_loader = torch.utils.data.DataLoader(
dataset=train_dataset,
batch_size=100,
shuffle=True,
num_workers=0
)
# ネットワークの構成、(Conv2d + ReLU + MaxPoolin)×2 + FC×2
args = {}
## conv layer
args'H1', args'W1' = 28, 28 # iput image size ## pooling, Window & Stride size
## FC layer
print(args, file=fp)
print(args)
# 学習
EPOCHS = 10
lr = 0.01
net = Net(args)
optimizer = torch.optim.SGD(net.parameters(), lr=lr)
loss = nn.MSELoss()
obj_hist = []
print(net, file=fp)
print(net)
print(optimizer, file=fp)
print(optimizer)
print('EPOCHS =', EPOCHS, file=fp)
print('EPOCHS =', EPOCHS)
time_t0 = time.time()
for epoch in range(1, EPOCHS + 1):
time_t1 = time.time()
for X, y in train_loader:
optimizer.zero_grad()
y_predict = net(X)
obj = loss(y_predict, y)
obj_hist.append(obj.item())
obj.backward()
optimizer.step()
if epoch%(EPOCHS//10) == 0:
print('progress =', int(epoch/EPOCHS*100),'%, EPOCH =', epoch, ', loss ={:.3e}'.format(obj.item()), ', time =', time.time() - time_t1, file=fp)
print('progress =', int(epoch/EPOCHS*100),'%, EPOCH =', epoch, ', loss ={:.3e}'.format(obj.item()), ', time =', time.time() - time_t1)
print('total time =', time.time() - time_t0, file=fp)
print('total time =', time.time() - time_t0)
#
def calc_accuracy(net, X_test, y_test):
y_test_predict = net.forward(X_test)
y_test_predict_max_index = y_test_predict.max(dim=1)1 y_test_predict_compare = y_test_predict_max_index == y_test
y_test_predict_accuracy = (y_test_predict_compare.sum() / len(y_test_predict_compare))
return y_test_predict_accuracy
#
result_accuracy = calc_accuracy(net, X_test, y_test)
print('accuracy = {:.8f}'.format(result_accuracy.item()), file=fp)
print('accuracy = {:.8f}'.format(result_accuracy.item()))
plt.plot(obj_hist, label='loss function')
plt.grid()
plt.legend()
plt.savefig(dirname + '/loss_function.svg')
torch.save(net, dirname + '/net_cnn_sp.pth') # ネットのパラメータを保存
fp.close()